-- card: 15168 from stack: in.3 -- bmap block id: 15445 -- flags: 4000 -- background id: 7337 -- name: SortFieldByItem ----- HyperTalk script ----- on opencard hide card field "source" put empty into card field "sorted" pass opencard end opencard on Install put ChooseTargetStack() into it InstallResource XFCN,SortFieldByItem,it end Install on closeCard hide msg end CloseCard -- part 2 (field) -- low flags: 01 -- high flags: 0007 -- rect: left=290 top=64 right=288 bottom=398 -- title width / last selected line: 0 -- icon id / first selected line: 0 / 0 -- text alignment: 0 -- font id: 3 -- text size: 9 -- style flags: 0 -- line height: 12 -- part name: unsorted -- part 3 (button) -- low flags: 00 -- high flags: 8003 -- rect: left=65 top=298 right=320 bottom=187 -- title width / last selected line: 0 -- icon id / first selected line: 0 / 0 -- text alignment: 1 -- font id: 0 -- text size: 12 -- style flags: 0 -- line height: 16 -- part name: SortFieldByItem ----- HyperTalk script ----- on mouseUp put empty into card field "sorted" put the ticks into t1 put SortFieldByItem(card field "unsorted",2) into card field "sorted" put the ticks into t2 put "time: "&t2-t1&&"ticks" get the number of lines in card field unsorted put " for "&it&" lines" after msg end mouseUp -- part 6 (button) -- low flags: 00 -- high flags: 8003 -- rect: left=299 top=298 right=320 bottom=438 -- title width / last selected line: 0 -- icon id / first selected line: 0 / 0 -- text alignment: 1 -- font id: 0 -- text size: 12 -- style flags: 0 -- line height: 16 -- part name: Show C Source ----- HyperTalk script ----- on mouseUp get the visible of card field "source" set the visible of card field "source" to not it if it is false then set the name of me to "Hide C Source" else set the name of me to "Show C Source" end if end mouseUp -- part 8 (field) -- low flags: 01 -- high flags: 0007 -- rect: left=395 top=64 right=288 bottom=490 -- title width / last selected line: 0 -- icon id / first selected line: 0 / 0 -- text alignment: 0 -- font id: 3 -- text size: 9 -- style flags: 0 -- line height: 12 -- part name: sorted -- part 9 (field) -- low flags: 01 -- high flags: 2007 -- rect: left=18 top=33 right=288 bottom=291 -- title width / last selected line: 0 -- icon id / first selected line: 0 / 0 -- text alignment: 0 -- font id: 3 -- text size: 10 -- style flags: 0 -- line height: 13 -- part name: Documentation -- part 7 (field) -- low flags: 81 -- high flags: 0007 -- rect: left=18 top=31 right=290 bottom=489 -- title width / last selected line: 0 -- icon id / first selected line: 0 / 0 -- text alignment: 0 -- font id: 3 -- text size: 10 -- style flags: 0 -- line height: 13 -- part name: Source -- part contents for card part 7 ----- text ----- /* SortFieldByItem1.0d1.c */ /* © Trustees of Dartmouth College */ /* written in LightSpeed C © Think Technologies, Inc */ /* by Roger Brown 3/2/88 Courseware Development Group 11/19/88 */ /* Distribution version. Source is for THINK C© version 4.0. */ /* version 1.0d1 uses international string comparison */ /* This is a HyperCard XFCN that sorts the lines of a HyperCard container alphabetically according to the value of a specified item in the line. There is no limit to the number of lines except for available memory. It uses the Lightspeed C quicksort function and it is quite fast! Only one pass is made over the data to find line starts. Case is ignored in this version. Syntax is: get SortFieldByItem(container,item) where container is any hypercard container (field, variable), presumed to be multi-lined. item is the number of the item in the line to use as the sort key. returns: a copy of the container sorted by line or error messages. ex. get SortField(card field 1,2) To compile: create a project with this,MacTraps, and the LSC® qsort.c file. Build as code resource type XFCN named SortFieldByItem. */ #include "MemoryMgr.h" #include "HyperXCmd.h" #include "XCmdGlue.inc.c" #include "SetUpA4.h" #define memoryError -1 /* marks a memory allocation error */ int *order; /* points to the line order array (in heap) */ Handle orderHandle; /* handle to the line order array */ int *lineStarts; /* points to array of line starts (in heap) */ Handle lsHandle; /* handle to the line starts array */ Handle theField; /* handle to the input copy of the container */ Handle theUCASEField; /* handle to an upper case version of container */ Handle DoSort(); /* the sorting routine */ long sortItem; /* the number of the sort item */ #define NULL 0L /* change a string to all upper case */ ucase(s) char *s; { int i; char c; for (i=0;i32768)) return FALSE; /* all characters must be 0..9,-,+ */ for (c=0;c57)) if ((s[c]!=45)&&(s[c]!=43)) return FALSE; } CtoPstr(s); StringToNum(s,n); return TRUE; } /* Get HyperCard comma delimited item i from item list string inStr. Return it in outStr */ /* item must be smaller than 255 characters */ GetHCItem(inStr,i,outStr) char *inStr,*outStr; int i; { int c; /* character pointer */ int len; /* length to scan */ int count; /* count of items found */ int j; /* item byte count */ Str255 temp; /* collect item here, hope its < 255 */ count = j = 0; /* initialize */ len = strlen(inStr); /* go this far, max */ for (c=0;c 255 characters."); return; } if (c==(len-1)) { /* last item, no comma */ count = count+1; break; } } } if (count < i) strcpy(outStr,""); /* no item there */ else { temp[j] = 0; /* make it a C string */ strcpy(outStr,temp); /* move to output string */ } return; } /* build a return result structure from a string */ ResultIs(paramPtr,theResult) XCmdBlockPtr paramPtr; char *theResult; { long len; Handle resultHandle; len = 1+strlen(theResult); resultHandle = NewHandle(len); BlockMove(theResult,*resultHandle,len); paramPtr->returnValue = resultHandle; } /* Get all line starts in one sweep, changing CRs to 0 bytes so that I have real C strings to work with later. Also process an upper case copy of the input data by changing CRs to 0s and upper casing everthing else. We process both copies because we want to sort the upper case version but reassemble the result from the original. Returns the number of lines found. */ GetLineStarts(source,ucSource) char *source,*ucSource; /* the data source and a copy to ucase */ { int c; /* character counter */ int l; /* line counter */ long startsSize; /* size of the line starts array */ /* allocate some memry to hold the line starts "array" */ startsSize = 128; /* arbitrary starting size */ lsHandle = NewHandle(startsSize*2); if (lsHandle==NULL) { /* handle error */ SysBeep(60); return memoryError; } HLock(lsHandle); lineStarts = (int *)*lsHandle; /* scan the input data to find line starts */ l = c = 0; *lineStarts = 0; /* first line starts at byte 0 */ while (source[c] != 0) { /* scan to end */ if (source[c]==13) { /* at end of a line */ l++; *(lineStarts+l) = c+1; /* next one starts here */ source[c] = 0; /* change cr to 0 */ ucSource[c] = 0; /* and do same to the ucase version */ if (l==startsSize-10) { /* need more room for line starts */ startsSize = startsSize + 128; HUnlock(lsHandle); SetHandleSize(lsHandle,startsSize*2); if (lsHandle==NULL) { /* oops, out of room */ SysBeep(60); return memoryError; } HLock(lsHandle); lineStarts = (int *)*lsHandle; /* it might have moved */ } } ucSource[c] = toupper(ucSource[c]); /* change to ucase in line */ c++; } if (source[c-1]==0) l--; /* last line might not have CR */ return l+1; } /* Compare line i and line j. This function is an input to qsort. */ compare(i,j) int i,j; { Str255 item1,item2; int len1,len2; GetHCItem(*theUCASEField+*(lineStarts+order[i]),(int)sortItem,item1); GetHCItem(*theUCASEField+*(lineStarts+order[j]),(int)sortItem,item2); len1 = strlen(item1); len2 = strlen(item2); return IUMagString(item1,item2,len1,len2); } /* Swap line i with line j. This function is an input to qsort. */ swap(i,j) int i,j; { int swap; swap = order[i]; /* We don't swap them in place, just */ order[i] = order[j]; /* their positions in the order array */ order[j] = swap; } /* Do the sort and return a handle to the sorted result */ Handle DoSort() { Handle tempField; /* handle to memory to build the result */ int i,j,next; int numLines; Str255 temp1; OSErr err; long orderSize; long test; char c; int sLen,last; /* make a copy of the data to convert to upper case */ theUCASEField = theField; err = HandToHand(&theUCASEField); if (err != noErr) { /* some memory problem */ tempField = NewHandle(32); /* hope it fits */ strcpy(*tempField,"Not enough memory to sort (1)"); return tempField; } HLock(theUCASEField); /* lock these down so we use pointers to them */ HLock(theField); /* get line starts, number of lines, and an uppercase copy */ numLines = GetLineStarts(*theField,*theUCASEField); if (numLines == memoryError) { /* some memory problem */ tempField = NewHandle(32); strcpy(*tempField,"Not enough memory to sort (2)"); return tempField; } /* allocate space for the order array */ orderSize = (numLines+1)*2; /* this is an integer array */ orderHandle = NewHandle(orderSize); if (orderHandle==NULL) { /* some memory problem */ tempField = NewHandle(32); strcpy(*tempField,"Not enough memory to sort (3)"); return tempField; } /* lock it down so we can use a pointer to it */ HLock(orderHandle); order = (int *)*orderHandle; /* initialize the order list */ for (i=0;iparams[0]); HLock(paramPtr->params[0]); theField = (Handle)paramPtr->params[0]; HLock(paramPtr->params[1]); strcpy(paramStr,*(paramPtr->params[1])); if (ValidStrToNum(paramStr,&sortItem)==TRUE) { /* do the sort */ paramPtr->returnValue = DoSort(); } else { strcpy(paramStr,"Error in item number"); ResultIs(paramPtr,paramStr); } /* clean up */ HUnlock (paramPtr->params[0]); HUnlock (paramPtr->params[1]); RestoreA4(); return; } -- part contents for card part 9 ----- text ----- SortFieldByItem version 1.0d1.c Roger Brown SortFieldByItem is an XFCN that alphabetically sorts the lines of any HyperCard container using a specified item on the line as a sort key. The inputs are a container and the number of the item to sort by. The output is a sorted copy of the container data. This XFCN will give the same result as SortField if there is only one item in each line and item 1 is the sort key. It assumes that the sort item will be no longer than 255 characters. If the sort item in a particular line begins with a space, it will appear first in the list, so BE CAREFUL! Similarly if a line does not have an item in the sort item position, it will appear first in the list. Like SortField, this XFCN is quick and there is no limit to the number of lines in the container, except for the absolute limit of available memory. INVOKING SortFieldByItem get SortFieldByItem(container,sortItem) where container is any HyperCard container item is the number of the item to use as a sort key EXAMPLE ex. put SortField(card field "source",2) into card field "destination" REVISION HISTORY 1.0d0 First public release. 1.0d1 Uses international string comparisons. -- part contents for card part 2 ----- text ----- Hanover,NH Boston,MA New York,NY San Diego,CA St. Louis,MO Seattle,WA Atlanta,GA Wilmington,DE Chicago,IL Houston,TX Denver,CO Columbus,OH Orlando,FL Washington,DC -- part contents for card part 8 ----- text ----- San Diego,CA Denver,CO Washington,DC Wilmington,DE Orlando,FL Atlanta,GA Chicago,IL Boston,MA St. Louis,MO Hanover,NH New York,NY Columbus,OH Houston,TX Seattle,WA